/*
 * BordLayout.cpp
 *
 *  Created on: Oct 23, 2008
 *      Author: tfannes
 */

#include "BordLayout.h"
#include <HexGrid.h>
#include <QWidgetItem>
#include "ElementButton.h"
#include "HexagonButton.h"
#include <IllegalBoardException.h>
#include <math.h>
#include <iostream>

BordLayout::BordLayout(QWidget * parent) :
	QLayout(parent)
{
	setHexagonRadius(80);
}

BordLayout::~BordLayout()
{
	qDeleteAll(arNormalItems);
	qDeleteAll(arHexagonItems);
	qDeleteAll(arCornerItems);
	qDeleteAll(arSideItems);

	arNormalItems.clear();
	arHexagonItems.clear();
	arCornerItems.clear();
	arSideItems.clear();
	arElementItems.clear();
}

ElementButton * BordLayout::getElementAt(const HexVector & position)
{
	// check if the position is valid
	if (HexGrid::CheckLocationType(position) == GridLocationInvalid) throw error::IllegalBoardException::CreateInvalidPositionException();

	// check if we already have something there
	if (arElementItems.containsInA(position)) return (ElementButton *) arElementItems.getBValue(position)->widget();

	ElementButton * newElement = 0;
	QWidgetItem * newItem = 0;

	// we don't, so create the right type

	if (HexGrid::CheckLocationType(position) == GridLocationHexagon) arHexagonItems << (newItem = new QWidgetItem(newElement = new HexagonButton()));
	//	if(HexGrid::CheckLocationType(position) == GridLocationCorner) arCornerItems << (newItem = new QWidgetItem(newElement = new CornerButton()));
	//	if(HexGrid::CheckLocationType(position) == GridLocationSide) arSideItems << (newItem = new QWidgetItem(newElement = new SideButton()));

	// add the element to the array
	arElementItems.insert(position, newItem);

	// set the right data for the element
	setElementLayoutData(newElement);

	return newElement;
}

void BordLayout::removeElementAt(const HexVector & position)
{
	// can we remove it, does it exist?
	if (!arElementItems.containsInA(position)) return;

	// get the element
	QLayoutItem * item = arElementItems.getBValue(position);

	// delete from the lists
	arElementItems.remove(position);
	if (HexGrid::CheckLocationType(position) == GridLocationHexagon) arHexagonItems.removeAll(item);
	if (HexGrid::CheckLocationType(position) == GridLocationCorner) arCornerItems.removeAll(item);
	if (HexGrid::CheckLocationType(position) == GridLocationSide) arSideItems.removeAll(item);

	// delete the item
	delete item;
}

QSize BordLayout::minimumSize() const
{
	return centerSize * 2;
}

QSize BordLayout::maximumSize() const
{
	return minimumSize();
}

QSize BordLayout::sizeHint() const
{
	return minimumSize();
}

void BordLayout::addItem(QLayoutItem * item)
{
	arNormalItems.push_back(item);
}

int BordLayout::setHexagonRadius(int proposedRadius)
{
	int xstep = proposedRadius / 2;
	int radius = xstep * 2;
	int ystep = (int) (radius * 0.8660254037844386468);
	int width = xstep * 4;
	int height = ystep * 2;

	// total properties
	layoutData.gridSize = QSize(width, height);

	// hexagon properties
	layoutData.hexagonSize = QSize(width + 1, height + 1);
	layoutData.hexagonPolygon.setPoints(6, xstep, 0, xstep*3, 0, width, ystep, xstep*3, height, xstep, height, 0, ystep);

	return radius;
}

void BordLayout::setGeometry(const QRect & rct)
{
	QRect tmpRect;

	QLayout::setGeometry(rct);

	// re-calculate all the data
	calculateSize();

	// set the right geometry for the background widgets
	for(int i = 0; i < arNormalItems. size(); i++)
		arNormalItems[i]->setGeometry(rct);

	// set the position for all the hexagons
	for(int i =0; i < arHexagonItems.size(); i++)
	{
		HexVector position = arElementItems.getAValue(arHexagonItems[i]);

		// get the new rect data
		if(HexGrid::CheckLocationType(position) == GridLocationHexagon)
			tmpRect = calculateHexagonGeometry(rct, position);


		// pass is to the element
		ElementButton * btn = (ElementButton *)arElementItems.getBValue(position)->widget();

		btn->setGeometry(tmpRect);
	}
}

QLayoutItem* BordLayout::itemAt(int i) const
{
	// bigger than 0
	if (i < 0) return 0;

	// first the normal widgets
	if (i < arNormalItems.size())
		return arNormalItems[i];

	// then the hexagons
	else if ((i -= arNormalItems.size()) < arHexagonItems.size())
		return arHexagonItems[i];

	// then the sides
	else if ((i -= arHexagonItems.size()) < arSideItems.size())
		return arSideItems[i];

	// and finaly the corners
	else if ((i -= arSideItems.size()) < arCornerItems.size())
		return arCornerItems[i];

	else return 0;
}

QLayoutItem* BordLayout::takeAt(int i)
{
	QLayoutItem * tmp = 0;

	// bigger than 0
	if (i < 0) return 0;

	// is it a normal item?
	if (i < arNormalItems.size())
	{
		tmp = arNormalItems[i];
		arNormalItems.removeAt(i);
	}

	// no, it is an hexagon
	else if ((i -= arNormalItems.size()) < arHexagonItems.size())
	{
		tmp = arHexagonItems[i];
		arHexagonItems.removeAt(i);

		arElementItems.remove(tmp);
	}

	// then the sides
	else if ((i -= arHexagonItems.size()) < arSideItems.size())
	{
		tmp = arSideItems[i];
		arSideItems.removeAt(i);

		arElementItems.remove(tmp);
	}

	// then the corners
	else if ((i -= arSideItems.size()) < arCornerItems.size())
	{
		tmp = arCornerItems[i];
		arCornerItems.removeAt(i);

		arElementItems.remove(tmp);
	}

	return tmp;
}

int BordLayout::count() const
{
	return arNormalItems.size() + arHexagonItems.size() + arSideItems.size() + arCornerItems.size();
}

void BordLayout::calculateSize()
{
	structure::HexVector minimum, maximum;

	float radiusSize = 0, tmpRadiusSize = 0;

	// find the most distant coordinates
	for (QMap<HexVector, QLayoutItem *>::const_iterator i = arElementItems.getMapAB().begin(); i != arElementItems.getMapAB().end(); i++)
		if ((tmpRadiusSize = i.key().getCenterDistance()) > radiusSize) radiusSize = tmpRadiusSize;

	// the size we will be using
	radiusSize = ceil(radiusSize) + 0.5f;

	centerSize = QSize(radiusSize * layoutData.gridSize.width(), radiusSize * layoutData.gridSize.height());
}

void BordLayout::setHexagonLayoutData(HexagonButton * button)
{
	button->SetClickableSurface(&(layoutData.hexagonPolygon));
	button->setMinimumSize(layoutData.hexagonSize);
	button->setMaximumSize(layoutData.hexagonSize);
}

void BordLayout::setElementLayoutData(ElementButton * button)
{
	HexagonButton * hexBtn = qobject_cast<HexagonButton *>(button);
	if(hexBtn != 0)	setHexagonLayoutData(hexBtn);
}

void BordLayout::setElementsLayoutData()
{
	for(int i = 0; i < arHexagonItems.size(); i++)
		setHexagonLayoutData((HexagonButton *)arHexagonItems[i]->widget());
}

QRect BordLayout::calculateHexagonGeometry(const QRect & rect, const HexVector & position) const
{
	float x = position.getX()/6.0f - (position.getY() + position.getZ())/12.0f;
	float y = (position.getZ() - position.getY())/6.0f;

	return QRect(x*layoutData.gridSize.width()/2 + centerSize.width(), y*layoutData.gridSize.height()/2 + centerSize.height(), layoutData.hexagonSize.width(), layoutData.hexagonSize.height());
}
QRect BordLayout::calculateCornerGeometry(const QRect & rect, const HexVector & position) const
{
	return QRect();
}
QRect BordLayout::calculateSideGeometry(const QRect & rect, const HexVector & position) const
{
	return QRect();
}
